home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Tele / C / Comet2.1.3 Folder / Comet / telnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-25  |  14.8 KB  |  728 lines  |  [TEXT/????]

  1. /*
  2.     Copyright Cornell University 1986.  All rights are reserved.
  3.  
  4.     As of 4/10/86:
  5.     This source file may have no changes from the M.I.T original
  6.     other than this notice; but it has been tested as part of 
  7.     Cornell's Aztec-C port.  See notice.h
  8.     
  9.     telnet.c contains the telnet layer of the application.
  10.     It also contains file transfer routines.
  11.  
  12. */
  13.  
  14. #include <em.h>
  15.  
  16. #include <cntldefs.h>
  17. #include <3270.h>
  18. #include <rcodes.h>
  19. #include "ft.h"
  20.  
  21. #define TELDATA        0
  22. #define TELCOM        1
  23. #define TELWONT        2
  24. #define TELWILL        3
  25. #define TELDO        4
  26. #define TELDONT        5
  27. #define TELNEGO        6
  28. #define TELNEGO1    7
  29. #define TELNEGO2    8
  30. #define TELNEGO3    9
  31.  
  32.  
  33. char sb_termtype[] = {TNIAC, 0xfa, 0x18, 0x00};
  34. char *sb_term[] = {
  35. "VT100",                        /* officially a "DEC-VT100" but not by termcap...*/
  36. "IBM-3278-",
  37. "H19",
  38. "VT102"
  39. };                                /* last entry repeated twice to indicate end of list */
  40. char sb_end[] = {TNIAC, 0xf0, 0x00};
  41.  
  42. /* 3 types of ibm 3270 which might be reported; -4 is 43 X 80, not supported 
  43.     due to size >32 rows (modflg is a long bit-array, alas) */
  44. char ibm_types[] = {
  45. '2',         /* 24 X 80 */
  46. '3',         /* 32 X 80 */
  47. '5'            /* 27 X 132 */
  48. };
  49.  
  50. int hostconncomplete();            /* the host connect action completion call */
  51.  
  52. wr_usr(buf, len, urg)
  53. unsigned char *buf;
  54. int len;
  55. int urg; 
  56. {
  57.     register unsigned int thechar;
  58.     register unsigned char * bufend;
  59.     register unsigned char * bufp;
  60.     unsigned char *com_begin;
  61.     int comcount;
  62.     struct ucb    *pucb;
  63.     
  64.     pucb = &emdp->ucb;
  65.  
  66.     bufend = buf + len;
  67.     com_begin = NULL;
  68.  
  69.     for (bufp = buf; bufp < bufend; bufp++) {
  70.         thechar = *bufp;
  71.         if (emdp->telmode == TELDATA) {
  72.             /* we eat up all data in this branch */
  73.             if (thechar == TNIAC) {
  74.                 com_begin = NULL;
  75.                 emdp->telmode = TELCOM;
  76.             }
  77.             else {
  78.                 /* deal with most likely case: data */
  79.  
  80.                 if (!emdp->tndata) {
  81.                     /* these are the first data bytes received */
  82.                     emdp->tndata = TRUE;
  83.                     if (!ibmtest())
  84.                         /* not 3270, guarantee terminal set to appropriate ASCII type */
  85.                         settermtype(emdp->termtype);
  86.                     if (!hostconncomplete(emdp->connmacro))
  87.                         termwake();                        /* make sure controls drawn */
  88.                 }
  89.                     
  90.                 if (emdp->icon_up)
  91.                     emalert();            /* highlight icon to show activity */
  92.  
  93.                 com_begin = bufp;
  94.                 for ( ; bufp < bufend && *bufp != TNIAC; bufp++) {
  95.                     /* find the next IAC or end of buffer */
  96.                     if (!emdp->tnbinary)
  97.                         /* mash the high bit down if not in binary mode */
  98.                         *bufp &= 0x7f;
  99.                     ;
  100.                 }
  101.                 comcount = bufp - com_begin;
  102.                 
  103.                 if (emdp->ibm_mode) {
  104.                     /* call the 3270 command processor w/the data */
  105.                     if (emdp->event_reg & TFTP_ON)
  106.                         tnftsave(com_begin, comcount);
  107.                     else
  108.                         cmd(com_begin, comcount);
  109.                 }
  110.                 else {
  111.                     (*emdp->emstr)(com_begin, comcount);
  112.                     emdp->hycnewdata = TRUE;
  113.                 }
  114.  
  115.                 if (bufp < bufend) {
  116.                     /* found IAC */
  117.                     emdp->telmode = TELCOM;
  118.                 }
  119.                 else
  120.                     break;
  121.             }
  122.         }
  123.         else {
  124.             switch (emdp->telmode) {
  125.                 case TELCOM: {
  126.                     switch (thechar) {
  127.                         case TNEOR: {
  128.                             if (emdp->ibm_mode) {
  129.                                 /* EOR signals 3270 end of record */
  130.                                 if (emdp->event_reg & TFTP_ON) {
  131.                                     tnftcomplete();
  132.                                 }
  133.                                 else {
  134.                                     cmdcomplete();
  135.                                     emdp->hycnewdata = TRUE;
  136.                                     /* (*emdp->screen_upd)(); 
  137.                                         delay to enhance performance when 
  138.                                         doing LIST etc which send screen as
  139.                                         up to 10 separate packets....*/
  140.                                 }
  141.                             }
  142.                             emdp->telmode = TELDATA;
  143.                             break;
  144.                         }
  145.                         case TNDO: {
  146.                             emdp->telmode = TELDO;
  147.                             break;
  148.                         }
  149.                         case TNDONT: {
  150.                             /* DONT */
  151.                             emdp->telmode = TELDONT;
  152.                             break;
  153.                         }
  154.                         case TNWILL: {
  155.                             emdp->telmode = TELWILL;
  156.                             break;
  157.                         }
  158.                         case TNWONT: {
  159.                             emdp->telmode = TELWONT;
  160.                             break;
  161.                         }
  162.                         case TNSB: {
  163.                             /* sub negotiation */
  164.                             emdp->telmode = TELNEGO;
  165.                             emdp->subnegofail = FALSE;
  166.                             break;
  167.                         }
  168.                         case TNAYT: {
  169.                             /* Am I here?  Send an AYT back! */
  170.                             (*emdp->putchar)(TNIAC);
  171.                             (*emdp->putchar)(TNAYT);
  172.                             (*emdp->putflush)();
  173.                             emdp->telmode = TELDATA;
  174.                             break;
  175.                         }
  176.                         case TNIAC: {
  177.                             /* it's a literal IAC */
  178.                             if (emdp->ibm_mode)
  179.                                 cmd(bufp, 1);
  180.                             else
  181.                                 (*emdp->emstr)(bufp, 1);
  182.                             emdp->telmode = TELDATA;
  183.                             break;
  184.                         }
  185.                         default: {
  186.                             emdp->telmode = TELDATA;
  187.                             break;
  188.                         }
  189.                     }
  190.                     break;
  191.                 }
  192.                 case TELNEGO: {
  193.                     if (thechar != OPTTERMTYPE) 
  194.                         emdp->subnegofail = TRUE;
  195.                     emdp->telmode = TELNEGO1;
  196.                     break;
  197.                 }
  198.                 case TELNEGO1: {
  199.                     if (thechar != TNSEND) 
  200.                         emdp->subnegofail = TRUE;
  201.                     emdp->telmode = TELNEGO2;
  202.                     break;
  203.                 }
  204.                 case TELNEGO2: {
  205.                     if (thechar != TNIAC) 
  206.                         emdp->subnegofail = TRUE;
  207.                     emdp->telmode = TELNEGO3;
  208.                     break;
  209.                 }
  210.                 case TELNEGO3: {
  211.                     int newtermtype;
  212.                     
  213.                     if (thechar != TNSBEND) {
  214.                         /* make sure end of subnegotiations */
  215.                         error("Sub negotiation not concluded");
  216.                         emdp->telmode = TELDATA;
  217.                         break;
  218.                     }
  219.                     if (!emdp->subnegofail) {
  220.                         /* tell the host what we are */
  221.                         if (!emdp->termset) {
  222.                             /* Multinet: ignore negotiation attempts if type fixed */
  223.                             if (emdp->termrepeat) {
  224.                                 emdp->termtype = -1;
  225.                                 emdp->termrepeat = FALSE;
  226.                             }
  227.                             newtermtype = emdp->termtype;
  228.                         
  229.                             while (++newtermtype < TERMTYPECOUNT) {
  230.                                 /* repeat ourselves, then go back to first terminal type */
  231.                                 if (!emdp->disableterm[newtermtype])
  232.                                     /* this type is enabled, report it */
  233.                                     break;
  234.                             }
  235.                             if (newtermtype == TERMTYPECOUNT) {
  236.                                 /* we have reached the end of the list, repeat emdp->termtype */
  237.                                 emdp->termrepeat = TRUE;
  238.                             }
  239.                             else
  240.                                 emdp->termtype = newtermtype;
  241.                         }
  242.                         
  243.                         telnet_sendstr(&sb_termtype[0]);
  244.                         (*emdp->putchar)(TNIS);                    /* imbedded zero ! */
  245.                         telnet_sendstr(sb_term[emdp->termtype]);
  246.                         if (emdp->termtype == TERM_3270)
  247.                             (*emdp->putchar)(ibm_types[emdp->ibm_type]);
  248.                         telnet_sendstr(&sb_end[0]);
  249.                         (*emdp->putflush)();
  250.                         
  251.                         switch (emdp->termtype) {
  252.                             case TERM_VT100:
  253.                             case TERM_VT102:
  254.                             case TERM_VT220:
  255.                             {
  256.                                 /* VT100, switch menus */
  257.                                 emdp->mode = VT100MODE;
  258.                                 emdp->vtmode = NORMMODE;
  259.                                 emdp->em = vt100;
  260.                                 emdp->emstr = vt100str;
  261.                                 break;
  262.                             }
  263.                             case TERM_3270: {
  264.                                 /* IBM 3270; wait to switch modes until EOR/BINARY */
  265.                                 break;
  266.                             }
  267.                             case TERM_H19: {
  268.                                 /* H19 */
  269.                                 emdp->mode = NORMMODE;
  270.                                 emdp->em = h19;
  271.                                 emdp->emstr = h19str;
  272.                                 break;
  273.                             }
  274.                         }
  275.                     }
  276.                     emdp->telmode = TELDATA;
  277.                     break;
  278.                 }
  279.                 case TELWONT: {
  280.                     switch(thechar) {
  281.                         case OPTECHO: {
  282.                             switch(pucb->u_echongo) {
  283.                                 case NORMALMODE: {
  284.                                     /* This host did not initiate echo negot - so respond */
  285.                                     if (pucb->u_echom != LOCAL)
  286.                                         echolocal(pucb);
  287.                                     break;
  288.                                 }
  289.                                 case RECHOREQ: {
  290.                                     /* Rejecting my IAC DO ECHO */
  291.                                     ttecholocal(pucb);
  292.                                     break;
  293.                                 }
  294.                             }            
  295.                             pucb->u_echongo = NORMALMODE;
  296.                             break;
  297.                         }
  298.                     }
  299.                     emdp->telmode = TELDATA;
  300.                     break;
  301.                 }
  302.                 case TELWILL: {
  303.                     switch(thechar) {
  304.                         case  OPTECHO: {
  305.                             switch (pucb->u_echongo) {
  306.                                 case NORMALMODE: {
  307.                                     /* This host did not initiate echo negot - so respond */
  308.                                     if (pucb->u_echom != REMOTE)
  309.                                         echoremote(pucb);
  310.                                     setsendm(EVERYC);
  311.                                     emdp->ucb.u_sendm = EVERYC;
  312.                                         /* echoremote needs every char sent to be useful! */
  313.                                         
  314.                                     break;
  315.                                 }
  316.                                 case LECHOREQ:
  317.                                     /* Rejecting my IAC DONT ECHO  (illegit) */
  318.                                     ttechoremote(pucb);
  319.                                     break;
  320.                             }            
  321.                             pucb->u_echongo = NORMALMODE;
  322.                             break;
  323.                         }
  324.                         case OPTBINARY:     {
  325.                             /* do binary (usually for 3270) */
  326.                             (*emdp->putchar)(TNIAC);
  327.                             (*emdp->putchar)(TNDO);
  328.                             (*emdp->putchar)(thechar);
  329.                             (*emdp->putflush)();
  330.                             
  331.                             emdp->tnbinary = TRUE;
  332.                             break;
  333.                         }
  334.                         case OPTEOR:     {
  335.                             /* do End of Record processing for 3270 */
  336.                             (*emdp->putchar)(TNIAC);
  337.                             (*emdp->putchar)(TNDO);
  338.                             (*emdp->putchar)(thechar);
  339.                             (*emdp->putflush)();
  340.                             
  341.                             emdp->tneor = TRUE;
  342.                             break;
  343.                         }
  344.                         case OPTSPGA:     {
  345.                             /* suppress Go Aheads */
  346.                             (*emdp->putchar)(TNIAC);
  347.                             (*emdp->putchar)(TNDO);
  348.                             (*emdp->putchar)(thechar);
  349.                             (*emdp->putflush)();
  350.                             break;
  351.                         }
  352.                         default: {
  353.                             (*emdp->putchar)(TNIAC);
  354.                             (*emdp->putchar)(TNDONT);
  355.                             (*emdp->putchar)(thechar);
  356.                             (*emdp->putflush)();
  357.                             break;
  358.                         }
  359.                     }
  360.                     emdp->telmode = TELDATA;
  361.                     break;
  362.                 }
  363.                 case TELDO: {
  364.                     (*emdp->putchar)(TNIAC);
  365.                     if (thechar == OPTTERMTYPE 
  366.                         || thechar == OPTECHO
  367.                         || thechar == OPTBINARY 
  368.                         || thechar == OPTTM 
  369.                         || thechar == OPTEOR
  370.                     )        
  371.                         (*emdp->putchar)(TNWILL);
  372.                     else 
  373.                         (*emdp->putchar)(TNWONT);
  374.                     (*emdp->putchar)(thechar);
  375.                     (*emdp->putflush)();
  376.                     emdp->telmode = TELDATA;
  377.                     break;
  378.                 }
  379.                 case TELDONT: {
  380.                     /* nada */
  381.                     switch (thechar) {
  382.                         case OPTECHO: {
  383.                             break;
  384.                         }
  385.                     }
  386.                     emdp->telmode = TELDATA;
  387.                     break;
  388.                 }
  389.             }
  390.         }    
  391.     }
  392.     if (comcount && !emdp->emdisable && !emdp->ibm_mode) {
  393.         /* if the user is holding a key down, make sure the cursor shows */
  394.         if (len <= 5 || autokey || autokeypersist) {
  395.             if (modflg) {
  396.                 /* in ASCII mode, update the screen immediately when small data */
  397.                 (*emdp->screen_upd)();
  398.             }
  399.         }
  400.         setcursor();        /* always update the cursor */
  401.     }
  402. }
  403.  
  404.  
  405. tn_init()
  406. {
  407.     ;
  408. }
  409.  
  410.  
  411. /* report that the tcp input buffer is full */
  412.  
  413. tcpfull() 
  414. {
  415.     emdp->ucb.u_tcpfull = 1;
  416.     prerr25("TCP Output buffer full");
  417. }
  418.  
  419.  
  420. telnetreset()
  421. {
  422.     extern int vt100();
  423.     extern int vt100str();
  424.  
  425.     termreset();
  426.     
  427.     emdp->termtype = -1;            /* show not negotiated yet */
  428.     emdp->termrepeat = FALSE;
  429.  
  430.     emdp->event_reg |= SYS_LOCK;
  431.  
  432.     emdp->telmode = TELDATA;
  433.     emdp->termset = FALSE;            /* no terminal type selected */
  434.     
  435.     emdp->tnbinary = FALSE;
  436.     emdp->tneor = FALSE;
  437.  
  438.     emdp->ucb.u_sendm = NEWLINE;    /* Telnet specs remote mode to start */
  439.     emdp->ucb.u_echom = LOCAL;
  440.  
  441. }
  442.  
  443.  
  444. /* reset the current terminal */
  445.  
  446. termreset()
  447. {
  448.     switch (emdp->termtype) {
  449.         /* reset/clear terminal emulator if it's been used */
  450.         case -1:
  451.         case TERM_VT100: 
  452.         case TERM_VT102: 
  453.         case TERM_VT220: 
  454.         {
  455.             /* -1 is telnet undefined */
  456.             emprep();
  457.             vt100reset();
  458.             newcursor();
  459.             emend();
  460.             break;
  461.         }
  462.         case TERM_3270: {
  463.             /* 3270 */
  464.             ibm3270reset();
  465.             clrstatus_info();
  466.             break;
  467.         }
  468.         case TERM_H19: {
  469.             /* h19 */
  470.             emprep();
  471.             h19reset();
  472.             newcursor();
  473.             emend();
  474.             break;
  475.         }
  476.     }
  477.  
  478.     emdp->tndata = FALSE;
  479.     emdp->termtype = 0;
  480.     emdp->em = vt100;
  481.     emdp->emstr = vt100str;
  482.  
  483.     ibmmode(FALSE);
  484. }
  485.                                     
  486.  
  487. echolocal(pucb)
  488. struct ucb    *pucb;
  489. {
  490.     (*emdp->putchar)(TNIAC);
  491.     (*emdp->putchar)(TNDONT);
  492.     (*emdp->putchar)(OPTECHO);
  493.     (*emdp->putflush)();
  494.     ttecholocal(pucb);
  495. }
  496.  
  497. ttecholocal(pucb)
  498. struct ucb    *pucb; 
  499. {
  500.  
  501.     pucb->u_echom = LOCAL;
  502.     setmecho(pucb->u_echom);
  503. }
  504.  
  505. echoremote(pucb)
  506. struct ucb    *pucb; 
  507. {
  508.     (*emdp->putchar)(TNIAC);
  509.     (*emdp->putchar)(TNDO);
  510.     (*emdp->putchar)(OPTECHO);
  511.     (*emdp->putflush)();
  512.     ttechoremote(pucb);
  513. }
  514.  
  515.  
  516.  
  517. ttechoremote(pucb)
  518. struct ucb    *pucb; 
  519. {
  520.     pucb->u_echom = REMOTE;
  521.     setmecho(pucb->u_echom);
  522. }
  523.  
  524.  
  525. /* do we have the preconditions required to negotiate 3270 emulation? */
  526.  
  527. ibmtest()
  528. {
  529.     if (emdp->termtype != TERM_3270 || !emdp->tneor || !emdp->tnbinary)
  530.         /* can't be a 3270 */
  531.         return(FALSE);
  532.     
  533.     if (ibm_make())                /* guarantee we have an emulator out there... */
  534.         return(FALSE);
  535.  
  536.     if (emdp->newconf) {
  537.         /* a new configuration will have the ASCII color map */
  538.         emdp->ibmcolormap = ibmcolormap;
  539.         colorupd(emdp);
  540.     }
  541.     emdp->termset = TRUE;
  542.     emdp->ibm_keymode = TRUE;
  543.     showsyslock();
  544.     ibmmode(TRUE);
  545.     setibm_keymode(TRUE);
  546.     ibmkeyenable();
  547.     
  548.     return(TRUE);
  549. }
  550.  
  551.  
  552. /* save the data in a buffer until we accumulate a complete block */
  553.  
  554. tnftsave(datap, len)
  555. unsigned char * datap;
  556. int len;
  557. {
  558.     BlockMove(datap, emdp->ftsaveptr, (long) len);
  559.     emdp->ftsaveptr += len;
  560. }
  561.  
  562.  
  563. /* we've received a complete command in FT mode, do it */
  564.  
  565. tnftcomplete()
  566. {
  567.     tnft(emdp->ftsavebuf, emdp->ftsaveptr - emdp->ftsavebuf);
  568.     emdp->ftsaveptr = emdp->ftsavebuf;
  569. }
  570.  
  571.  
  572. /* we've made a Telnet connection and need to execute a macro; the 
  573.     macro format is identical to an ordinary key macro */
  574.  
  575. hostconncomplete(hact)
  576. Handle hact;
  577. {
  578.     struct token * tkptr;
  579.     int actcount;
  580.     
  581.     if (hact == NULL)
  582.         return(FALSE);
  583.         
  584.     /* add the macro acts to the action queue */
  585.     HLock(hact);
  586.     
  587.     tkptr = (struct token *) (*hact + 4);
  588.     actcount = (GetHandleSize(hact) - 4) / 2;
  589.     
  590.     while (actcount-- > 0) {
  591.         putaction(tkptr->class, tkptr->entry);
  592.         tkptr++;
  593.     }
  594.     
  595.     HUnlock(hact);
  596.     
  597.     putaction(RSLT_EMC, EM_RESTORE);
  598.     putaction(RSLT_EMC, EM_SHOW);
  599.     pr25(0, "Executing logon macro... press Command-. to Cancel");
  600.     /* the macro must be serviced promptly, since the first thing it might
  601.         do is disable the terminal */
  602.         
  603.     bkrd_token_service();
  604.     
  605.     return(TRUE);
  606. }
  607.  
  608.  
  609. /* we are closing and need to execute the close macro; the 
  610.     macro format is identical to an ordinary key macro */
  611.  
  612. hostclosemacro(hact)
  613. Handle hact;
  614. {
  615.     struct token * tkptr;
  616.     int actcount;
  617.     
  618.     if (hact == NULL)
  619.         return(FALSE);
  620.         
  621.     /* add the macro acts to the action queue */
  622.     HLock(hact);
  623.     
  624.     tkptr = (struct token *) (*hact + 4);
  625.     actcount = (GetHandleSize(hact) - 4) / 2;
  626.     
  627.     while (actcount-- > 0) {
  628.         putaction(tkptr->class, tkptr->entry);
  629.         tkptr++;
  630.     }
  631.     
  632.     HUnlock(hact);
  633.     
  634.     putaction(RSLT_EMC, EM_CLOSE);
  635.     pr25(0, "Executing close macro... press Command-. to interrupt");
  636.     return(TRUE);
  637. }
  638.  
  639.  
  640. /* send a string of characters */
  641.  
  642. telnet_sendstr(strp)
  643. char * strp;
  644. {
  645.     for ( ; *strp; strp++) {
  646.         if ((*emdp->putchar)(*strp) ) {
  647.             return(-1);
  648.         }
  649.     }
  650. }
  651.  
  652.  
  653. /* select the first valid ASCII terminal type from the list of types */
  654.  
  655. gettermtype()
  656. {
  657.     int count;
  658.     
  659.     if (emdp->ibm_mode)
  660.         return;
  661.         
  662.     for (count = 0; count <= TERMTYPECOUNT; count++) {
  663.         if (emdp->disableterm[count])
  664.             continue;
  665.             
  666.         if (count == TERM_3270)
  667.             /* it's never valid to change to a 3270 */
  668.             continue;
  669.         else
  670.             break;
  671.     }
  672.     if (count == TERMTYPECOUNT)
  673.         /* none enabled, use default */
  674.         count = 0;
  675.         
  676.     settermtype(count);
  677. }
  678.  
  679.  
  680. /* set the terminal procedure pointers & modes */
  681.  
  682. settermtype(termid)
  683. int termid;
  684. {
  685.     if (emdp->ibm_mode)
  686.         return;
  687.         
  688.     emdp->termset = TRUE;
  689.     emdp->event_reg = 0;        /* clear this to allow output */
  690.     
  691.     switch (termid) {
  692.         case TERM_VT100: 
  693.         case TERM_VT102: 
  694.         case TERM_VT220: 
  695.         {
  696.             /* VT100 */
  697.             emdp->mode = VT100MODE;
  698.             emdp->vtmode = NORMMODE;
  699.             emdp->em = vt100;
  700.             emdp->emstr = vt100str;
  701.             break;
  702.         }
  703.         case TERM_3270: {
  704.             /* IBM 3270; wait to switch modes until EOR/BINARY */
  705.             break;
  706.         }
  707.         case TERM_H19: {
  708.             /* H19 */
  709.             emdp->mode = NORMMODE;
  710.             emdp->em = h19;
  711.             emdp->emstr = h19str;
  712.             break;
  713.         }
  714.         default: {
  715.             /* VT100 */
  716.             termid = TERM_VT100;
  717.  
  718.             emdp->mode = VT100MODE;
  719.             emdp->vtmode = NORMMODE;
  720.             emdp->em = vt100;
  721.             emdp->emstr = vt100str;
  722.             break;
  723.         }
  724.     }
  725.     emdp->termtype = termid;
  726.     setibm_keymode(emdp->ibm_keymode);
  727.     setcontext(emdp);
  728. }